配合分支:day21/start,Repo: 按我
心情可不可以改?現在新增日記,心情都是固定的,日記本身的「心情」也不能改,就趁這個機會來調整吧。
前一陣子介紹過 sealed class 用來做「狀態」的區分。也有另外一種比較輕量的方式能做,叫做 enum class。它很適合用來給 Entity 裡頭,任何可以「窮舉」的狀態。 enum class 很適合實作「心情」這個資料。
直接用案例來說明,新增 Mood.kt,內容填入:
enum class Mood(val displayName: String) {
CALM("平靜"),
FOCUSED("專注"),
IMPRESSED("震撼")
}
這代表這個 enum 有三個狀態:CALM、FOCUSED、IMPRESSED 三者,enum class 可以帶一個變數,這裡就用 displayName 這個字串來作為範例。
接著把 DiaryEntry.kt Entity 的 mood 字串,從 String 改成這個 enum class:
val mood: Mood // 👈🏼 這個改成 Mood
先著就是牽一髮而動全身,畢竟改了很深沉的東西。不過不用擔心,先從資料層的寫入/讀取開始調整。
資料寫入以及讀取,只需要來看 LocalDiaryStorage 這個 class 即可。
專注於 override fun save() {} 這個 save 的 Function,切記 JSON 是「文字檔案」,這也是為何 Mood 還需要 displayName 這個 String。
// before
jsonObject.put("mood", entry.mood)
// after
jsonObject.put("mood", entry.mood.displayName) // 👈🏼 改為 displayName
這樣一樣可以寫入字串。
專注於調整 override fun load() {} 這個 load 的 Function。這一段比較棘手的地方是需要將文字轉換回 Enum。文字有可能會遇到隨意亂寫的情況,故都需要加上處理「不知道這是什麼東西」的例外狀況,這時就 throw 錯誤出去外面就好。

心情從單純的字串,變成了 enum class。調整方式很單純,比如:
日記卡片的:
// before
Text(text = "心情:${entry.mood}")
// after,直接去拿 displayName 就好
Text(text = "心情:${entry.mood.displayName}")
ViewModel 在產生 Sample Data 時也用了一些,這邊調整就可以很容易看出 enum class 好用之處。打個比方像是建立新照片日記時塞給他的「平靜」預設值。
val newEntry = DiaryEntry(
photo = draftPhoto,
title = normalizedTitle,
note = normalizedNote,
mood = "平靜",
createdAt = LocalDateTime.now()
)
現在 Mood 變成一個 enum,則直接改成 Mood.CALM 就好,其他的依樣畫葫蘆。
配合分支:day21/mood-model,Repo: 按我
接下來來加入一個下拉選單,可以自由選擇心情。

JSON 寫資料的部分已經完成了,這一塊全部都是 View 這邊的工(畫面的),牽扯到「畫面狀態」所以也需要調整 ViewModel。先在 ViewModel 紀錄新增日記時「目前選的心情是哪個」。

有了紀錄心情的 State 後,其他就簡單了,就跟 Title 和 Note 的做法一樣,製作新日記時寫入即可。
val newEntry = DiaryEntry(
photo = draftPhoto,
title = normalizedTitle,
note = normalizedNote,
mood = draftMood, // 👈🏼 改成 draftMood 即可
createdAt = LocalDateTime.now()
)
接下來更新 ComposeView 這一側。有鑒於今天是第 21 天了,大家應該已經有「資料流」的概念。不外乎就是將「狀態」傳入 ComposeView,而 ComposeView 透過 callback function 與內部其他元件溝通(不是畫面的)。
先加入這個下拉元件:

請在新建照片日記的 DiaryForm 加入 MoodDropdown 將相對應的資料流串上即可:

就將這個「調整心情的功能加上去啦」。
如果想在清單中的日記卡片,也加上心情下拉選單,該怎麼做呢?(解答在 GitHub Repo 之中)
enum class 把可以「窮舉」的狀態列出來;心情只有少數幾種,很適合用它取代原本的字串。CALM、FOCUSED、IMPRESSED),比任意字串更不容易打錯。displayName 存「平靜/專注/震撼」等顯示文字,與 Enum 名稱分開。mood 從 String 改成 Mood;型別一改會「牽一髮而動全身」,需要逐步調整。entry.mood.displayName,因為 JSON 只能存文字,不能直接存 Enum。throw 丟出去,處理「不知道這是什麼東西」的情況。draftMood 記錄「目前選的心情」,跟 Title、Note 的做法一樣。Mood.CALM 當「平靜」預設值,取代原本的字串 "平靜"。